//
//  NSObject+ZCKVO.m
//  DebugDemo
//
//  Created by XFB on 2018/11/21.
//  Copyright © 2018年 ZhouCheng. All rights reserved.
//

#import "NSObject+ZCKVO.h"
# import <objc/message.h>

@implementation NSObject (ZCKVO)


/**
 <#Description#>

 @param observer <#observer description#>
 @param keyPath <#keyPath description#>
 @param options <#options description#>
 @param context <#context description#>
 */
- (void)ZC_addObserver:(NSObject *)observer
            forKeyPath:(NSString *)keyPath
               options:(NSKeyValueObservingOptions)options
               context:(nullable void *)context
{
    // 1.创建一个类
    NSString *oldClassName = NSStringFromClass(self.class);
    NSString *newClassName = [@"zcKVO_" stringByAppendingString:oldClassName];
    Class myClass = objc_allocateClassPair(self.class, newClassName.UTF8String, 0);
    
    // 注册类
    objc_registerClassPair(myClass);
    
    // 2.重写setName方法
    
    /**
     参数

     @param class 给哪个类添加方法
     @param sel 方法编号
     @param imp 方法实现(函数指针!)
     @param type 返回值类型
     @return
     */
    class_addMethod(myClass, @selector(setName:), (IMP)setName, "v@:@");
    
    // 3.修改isa指针
    object_setClass(self, myClass);

    // 4.将观察者保存到当前对象
    objc_setAssociatedObject(self, @"observer", observer, OBJC_ASSOCIATION_ASSIGN);
}

void setName(id self, SEL _cmd, NSString *newName) {

    Class class = [self class];
    
    object_setClass(self, class_getSuperclass(class));
    
    objc_msgSend(self, @selector(setName:), newName);
    
    /// 调用父类的setName 方法
    // 观察者
    id observer = objc_getAssociatedObject(self, @"observer");

    if (observer) {
        objc_msgSend(observer, @selector(observeValueForKeyPath:ofObject:change:context:), @"name", self, @{@"new" : newName, @"kind":@1}, nil);
    }
    
    /// 改回子类
    object_setClass(self, class);
}

@end
